

local xml = {};


local xml_tag_begin = "<";
local xml_tag_end = ">";

function string_at(str, i)
    return string.sub(str, i, i);
end

function string_sub(str, i, j)
    return string.sub(str, i, j);
end

function parse_tag(tag_str, tagnode)
    tagnode.attr = tagnode.attr or {};
    local attr = tagnode.attr;
    for key, value in string.gmatch(tag_str, [[ (%w+)%s*=%s*%"([^"]+)%"]]) do
        attr[key] = value;
    end
    -- for key, value in string.gmatch(tag_str, [[ (%w+)%s*=%s*%'([^']*)%']]) do
    --     print(key, value);
    --     attr[key] = value;
    -- end
    -- for key, value in string.gmatch(tag_str, [[ (%w+)%s*=%s*([%d%a]+)]]) do
    --     print(key, value);
    --     attr[key] = value;
    -- end
    -- for key, value in string.gmatch(tag_str, [====[ (%w+)[%s>]%s*[^=]]====]) do
    --     print(key);
    -- end
end

function from_string(str, start_index, parent_tag_node)
    str = str or "";
    start_index = start_index or 1;
    parent_tag_node = parent_tag_node or {};
    -- tag_begin
    local tag_begin_start_index, tag_begin_end_index = string.find(str, "<%a+[^>]*>", start_index, false);
    if (not tag_begin_start_index) then return true, start_index, parent_tag_node end
    start_index = tag_begin_end_index + 1;
    -- subtag_begin
    local subtag_begin_start_index, subtag_begin_end_index = string.find(str, "<%a+[^>]*>", start_index, false);
    -- tag_end
    local tag_end_start_index, tag_end_end_index = string.find(str, "</%a+>", start_index, false);

    local tag_node = {};
    local tag_begin_str = string_sub(str, tag_begin_start_index, tag_begin_end_index);
    local tag_begin_name = string.match(tag_begin_str, "<(%a+)");

    if (not tag_end_start_index) then
        print("tag syntax error:", tag_begin_str)
        return false, start_index, parent_tag_node;
    end
    print("tag_begin_str:", tag_begin_str)
    if (subtag_begin_start_index and subtag_begin_start_index < tag_end_start_index) then
        local ok, cur_start_index  = from_string(str, start_index, tag_node);
        if (not ok) then return false, cur_start_index, parent_tag_node end 
        start_index = cur_start_index;
    end

    -- print("tag end:", string_sub(str, start_index))
    tag_end_start_index, tag_end_end_index = string.find(str, "</%a+>", start_index, false);
    if (not tag_end_start_index) then
        print("tag syntax error:" .. tag_begin_str);
        return false, start_index, parent_tag_node;
    end
    local tag_end_str = string_sub(str, tag_end_start_index, tag_end_end_index);
    print("tag_end_str:", tag_end_str);
    local tag_end_name = string.match(str, "</(%a+)", start_index);
    if (tag_begin_name ~= tag_end_name) then
        print("tag not match: " .. tag_begin_name .. (tag_end_name or ""));
        return false, start_index, parent_tag_node;
    end
    tag_text = string_sub(str, tag_begin_end_index + 1, tag_end_start_index - 1);
    tag_text = string.gsub(tag_text, "^%s*", "");
    tag_text = string.gsub(tag_text, "%s*$", "");
    tag_node.name = tag_begin_name;
    tag_node.text = tag_text ~= "" and tag_text or nil;
    parse_tag(string_sub(str, tag_begin_start_index + string.len(tag_begin_name) + 1, tag_begin_end_index - 1), tag_node);
    if (parent_tag_node ~= nil) then table.insert(parent_tag_node, tag_node) end
    start_index = tag_end_end_index + 1;
    print("tag finish:", string_sub(str, start_index));
    return from_string(str, start_index, parent_tag_node);
end

function xml.to_string()
end

function xml.from_string(str, start_index, tag_end_start_index)
    local _, _, tag_node = from_string(str, 1, {});
    commonlib.echo(tag_node)
end

function xml.to_file()
end

function xml.from_file()
end


-- xml.from_string([[<div style="width: 100%;" key=1><div>text</div><button></button></div>]])